<template>
<div>
  <!--三级分类选择框对应的卡片-->
  <el-card>
    <!--showList为true 代表显示列表界面  三级分类不能禁用 disabled为false-->
    <CategorySelector @categoryChange="categoryChange" ref="cs"></CategorySelector>
  </el-card>

  <!--一个三级分类对应的属性列表-->
  <el-card style="margin: 20px 0" v-show="showList">
    <!--当category3Id为空时 当前按钮要禁用 disabled的值为true-->
    <el-button type="primary" icon="el-icon-circle-plus-outline"  @click="toAdd"
               :disabled="!category3Id">添加属性</el-button>

    <el-table :data="tableData" border v-loading="loading"
              style="margin: 10px 0">
      <el-table-column type="index" label="序号" width="80" align="center"></el-table-column>
      <el-table-column label="属性名称" align="center" prop="attrName"></el-table-column>
      <el-table-column label="属性值列表"  align="center">
        <template slot-scope="{ row, column, $index }">
          <el-tag type="info" v-for="item in row.attrValueList" style="margin-left: 10px">
            {{item.valueName}}
          </el-tag>
        </template>
      </el-table-column>
      <el-table-column label="操作" align="center">
        <template slot-scope="{row}">
          <HintButton type="primary" icon="el-icon-edit"
                      size="mini" title="修改" @click="toEdit(row)"></HintButton>

          <el-popconfirm :title="`确定要删除${row.attrName}吗？`" @onConfirm="delAttr(row.id)">
            <HintButton  slot="reference" type="danger" icon="el-icon-delete" size="mini" title="删除"></HintButton>
          </el-popconfirm>
        </template>
      </el-table-column>
    </el-table>
  </el-card>

  <!--新增属性和修改属性对应的界面-->
  <el-card style="margin: 20px 0" v-show="!showList">
    <el-form inline>
      <el-form-item label="属性名">
        <el-input placeholder="请输入属性名" v-model="attr.attrName"></el-input>
      </el-form-item>
    </el-form>

    <!--当前这个按钮 在attr.attrName为空时；是要禁用的; disabled应该为true-->
    <el-button type="primary"  :disabled="!attr.attrName"
               icon="el-icon-circle-plus-outline"
               @click="addAttrVal">添加属性值</el-button>
    <el-button @click="cancle">取消</el-button>

    <el-table border :data="attr.attrValList" style="margin: 10px 0">
      <el-table-column type="index" label="序号" width="80" align="center"></el-table-column>
      <el-table-column label="属性值名称" align="center">
          <template slot-scope="{row,$index}">
            <div v-if="!row.isEdit" @dblclick="Show2Edit(row,$index)">{{row.valueName}}</div>
            <el-input v-else  :ref="`input${$index}`"
                      v-model="row.valueName"
                      @keyup.enter.native="toSpan(row,$index)"
                      @blur="toSpan(row,$index)"></el-input>
          </template>
      </el-table-column>
      <el-table-column label="操作" align="center">
        <template slot-scope="{row,$index}">
          <el-popconfirm :title="`确定要删除${row.valueName}吗？`"
                         @onConfirm="delAttrVal($index)">
            <HintButton slot="reference" title="删除" type="danger" size="mini" icon="el-icon-delete"></HintButton>
          </el-popconfirm>
        </template>
      </el-table-column>
    </el-table>

    <!--当前这个按钮 在attr.attrName为空 或 在attr.attrValList为空时；
        是要禁用的; disabled应该为true-->
    <el-button type="primary" :disabled="disabledForSave" @click="save">保存</el-button>
    <el-button @click="cancle">取消</el-button>
  </el-card>
</div>
</template>

<script>
  import cloneDeep from "lodash/cloneDeep.js"
  export default {
  name: 'AttrList',
  data(){
    return {
      category1Id:"", //一级分类的id
      category2Id:"", //二级分类的id
      category3Id:"", //三级分类的id
      tableData:[],   //三级分类对应的属性列表
      loading:false,   //是否出现loading效果
      showList:true,   //代表属性列表是否显示（控制着新增&修改界面）

      // 新增&修改界面的数据抽象
      attr:{
        attrName:'',
        attrValList:[] // [{valueName:"属性值"}]
      },

      //同步dog1 dog3的状态
      Dog2:false
    }
  },
  computed:{
    disabledForSave(){
      //判断初始化 和 光标从属性值输入框中移除时 是否出错了
      let Dog4 = false;
      let index = this.attr.attrValList.length -1;
      if(index>=0){
        let lastRow = this.attr.attrValList[index];
        let Dog1 = lastRow.valueName.trim() === "";
        let Dog3 = this.attr.attrValList.filter(item =>item.valueName === lastRow.valueName).length >=2;
        Dog4 = Dog1 || Dog3;
      }else{
        Dog4 = false;
      }
      //保存按钮在attr.attrName为空 或 在attr.attrValList为空 或 在输入模式时出错 都要禁用
      return !this.attr.attrName || this.attr.attrValList.length===0 || Dog4;
    }
  },
  methods:{
    //点击进行新增&编辑属性
    async save(){
      const {id} = this.row;
      //准备新增&修改的数据
      const data = {
        attrName:this.attr.attrName,
        attrValueList:this.attr.attrValList,
        categoryId:this.category3Id,
        categoryLevel:3,
        id
      }

      await this.$API.attrs.addOrUpdate(data);

      this.$message({
        message:"新增成功",
        duration:2000
      })

      //新增界面关闭 刷新界面
      this.showList = true;
      await this.getAttrs()
    },
    //点击删除属性
    async delAttr(id){
       await this.$API.attrs.delAttr(id)
       this.$message({
         message:"删除成功",
         duration:2000
       });
       //重新刷新界面
       await this.getAttrs()
    },
    //点击删除属性值
    delAttrVal(index){
      this.attr.attrValList.splice(index,1)
    },
    //点击取消按钮触发
    cancle(){
      this.showList=true;
      setTimeout(()=>{
        this.Dog2=false
      })
    },
    //从显示模式变为编辑模式
    Show2Edit(row,index){
      // 当出现过错误提示后 不能继续添加（Dog1还醒着的时候不能添加）
      if(this.Dog2) return;

      //从显示模式变为编辑模式
      //编辑时 部分数据是从数据库中读取出来的 本身没有isEdite属性
      //给这部分数据要添加isEdite属性 一定要使用$set方法 要添加响应式属性 不然界面无法更新
      if(row.hasOwnProperty("isEdit")){
        row.isEdit = true;
      }else{
        this.$set(row,"isEdit",true)
      }
      //重新获取焦点
      this.$nextTick(()=>{
        this.$refs[`input${index}`].focus()
      })
    },
    //从编辑模式变为显示模式
    toSpan(row,index){
      //狗狗1号： 咬什么逻辑？ 当输入的内容为空时;咬住
      let Dog1 = row.valueName.trim() === "";
      if(Dog1){
        this.Dog2 = Dog1;
        this.$message.error({
          message:"属性值名称不能为空",
          duration:2000
        })
        //让当前输入框重新获取焦点
        this.$refs[`input${index}`].focus()
        return
      }

      //狗狗3号: 咬什么逻辑? 输入的内容不能重复
      let Dog3 = this.attr.attrValList.filter(item =>item.valueName === row.valueName).length >=2;
      if(Dog3){
        this.Dog2 = Dog3;
        this.$message.error({
          message:"属性值名称不能重复",
          duration:2000
        })
        //让当前输入框重新获取焦点
        this.$refs[`input${index}`].focus()
        return
      }

      //重置Dog2
      this.Dog2 = false;
      //从编辑模式变为显示模式
      row.isEdit=false;
    },
    //在新增&修改界面 添加属性值
    addAttrVal(){
      // 当出现过错误提示后 不能继续添加（Dog1还醒着的时候不能添加）
      if(this.Dog2) return;

      // 给attrValList加一项
      let attrVal = {
        valueName:"", //valueName是需要传递给后台接口的
        isEdit:true      //isEdit是用来控制界面的  当前属性值代表的行到底处于编辑模式还是显示模式
      }
      this.attr.attrValList.push(attrVal)
      //让最新的那个输入框自动获取焦点
      this.$nextTick(()=>{
        this.$refs[`input${this.attr.attrValList.length-1}`].focus()
      })
    },
    //去修改界面
    toEdit(row){
      this.showList = false;
      //携带row数据 去 save逻辑
      this.row = row;
      //回显表单
      this.attr.attrName = row.attrName
      //直接将一个对象的引用传递了过去  会导致数据的错乱
      this.attr.attrValList = cloneDeep(row.attrValueList)
    },
    //去新增界面
    toAdd(){
      this.showList = false;
      //清除表单
      this.row = {};
      this.attr = {
        attrName:'',
        attrValList:[]
      }
    },
    //当三级分类中任意一级产生改变时触发的回调
    //categoryId ：对应分类的id
    //level ：哪一级分类产生改变
    async categoryChange({categoryId, level}){
      switch (level){
        case 1:
          //清空列表 清空23级分类的id
          this.tableData = [];
          this.category2Id="";
          this.category3Id="";

          this.category1Id = categoryId;
          break;
        case 2:
          //清空列表 清空3级分类的id
          this.tableData = [];
          this.category3Id="";

          this.category2Id = categoryId;
          break;
        case 3:
          this.category3Id = categoryId;
          //发送请求获取属性列表
          await this.getAttrs()
          break;
      }
    },
    //发送请求获取三级分类对应的属性列表
    async getAttrs(){
      //发送请求获取三级分类对应的属性列表
      const {category1Id,category2Id,category3Id} = this;
      this.loading = true;
      const {data} = await this.$API.attrs.getAttrs({category1Id,category2Id,category3Id})
      this.loading = false;
      this.tableData = data;
    }
  },
  /*async mounted(){
    await this.getAttrs()
  },*/
  watch:{
    showList(val){
      this.$refs.cs.disabled = !val;
    }
  }
}
</script>
